﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Creation;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.Controls;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchUtils.Utils;
using YJKRevitDimensionText.Forms;

namespace YJKRevitDimensionText.DimCreator
{
	public class DimensionCreator
	{
		public DimensionCreator(UIApplication application)
		{
			this.m_uiApplication = application;
			this.m_uiDocument = application.ActiveUIDocument;
			this.m_application = application.Application;
			this.m_document = this.m_uiDocument.Document;
			this.m_appCreator = application.Application.Create;
			this.m_docCreator = application.ActiveUIDocument.Document.Create;
		}

		public Result DoorWindowDim(DlgDoorWindowDim dlg)
		{
			XYZ xyz = null;
			XYZ xyz2 = null;
			if (DimPublicFunc.PickPoint(this.m_uiDocument, "点取穿过墙或轴线的起点P1：", ref xyz) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			if (DimPublicFunc.PickPoint(this.m_uiDocument, "点取穿过墙或轴线的终点P2：", ref xyz2) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			xyz2 = new XYZ(xyz2.X, xyz2.Y, xyz.Z);
			if (xyz.DistanceTo(xyz2) < 0.001)
			{
				YJKMessageBox.Show("两点不能相距太近，请重新点取。");
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			List<Wall> list = null;
			if (dlg.SelectWallType == 0)
			{
				List<Grid> list2 = DimPublicFunc.LineCrossGrids(this.m_uiApplication, xyz, xyz2, false);
				if (list2 == null || list2.Count < 1)
				{
					YJKMessageBox.Show("起终点之间没有轴线。");
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				if (list2.Count > 1)
				{
					YJKMessageBox.Show("起终点之间只能有一道轴线。");
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				List<Wall> list3 = this.WallsOnAxis(list2[0], xyz.Z);
				if (list3 == null || list3.Count < 1)
				{
					YJKMessageBox.Show("轴线上没有墙体。");
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				list = this.GetWallOnLevel(list3, this.m_document.ActiveView.GenLevel.Id);
				if (list == null || list.Count < 1)
				{
					list = this.GetWallsOnTopLevel(list3);
				}
			}
			else
			{
				List<Wall> list4 = (from w in new FilteredElementCollector(this.m_document, this.m_document.ActiveView.Id).OfClass(typeof(Wall))
				where RevitElementExtension.GetParameter(w, BuiltInParameter.ELEM_CATEGORY_PARAM).AsValueString() == "墙"
				select w as Wall).ToList<Wall>();
				List<Wall> list5 = DimPublicFunc.LineCrossWalls(this.m_uiApplication, list4, xyz, xyz2);
				if (list5 == null || list5.Count < 1)
				{
					YJKMessageBox.Show("起终点之间没有墙体。");
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				List<Wall> list6 = this.GetWallOnLevel(list5, this.m_document.ActiveView.GenLevel.Id);
				if (list6 == null || list6.Count < 1)
				{
					list6 = this.GetWallsOnTopLevel(list5);
				}
				Wall maxThickWall = this.GetMaxThickWall(list6);
				list = new List<Wall>();
				list.Add(maxThickWall);
				List<Wall> list7 = new List<Wall>();
				list7.AddRange(list4);
				DimPublicFunc.WallsConnectOneLine(maxThickWall, 0, false, list7, ref list);
				DimPublicFunc.WallsConnectOneLine(maxThickWall, 1, false, list7, ref list);
			}
			this.FilterWallWithoutDoorAndWind(ref list);
			if (list.Count < 1)
			{
				YJKMessageBox.Show("墙上没有可标注的门窗", MessageBoxButtons.OK);
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			XYZ xyz3 = null;
			XYZ xyz4 = null;
			DimPublicFunc.GetWallsEndPoint(list, ref xyz3, ref xyz4);
			DimPublicFunc.SortPoint(ref xyz3, ref xyz4);
			xyz3 = new XYZ(xyz3.X, xyz3.Y, xyz.Z);
			xyz4 = new XYZ(xyz4.X, xyz4.Y, xyz.Z);
			XYZ xyz5 = Geometry.CalculateFootPoint(xyz3, xyz4, xyz2);
			XYZ xyz6 = (xyz2 - xyz5).Normalize();
			if (xyz6.IsAlmostEqualTo(XYZ.Zero))
			{
				YJKMessageBox.Show("选择的两个点必须在墙体两侧");
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			XYZ xyz7 = this.FindNearDimInter(xyz5, xyz2);
			if (xyz7 != null)
			{
				xyz2 = xyz7 - xyz6 * AssistFunc.mmToFeet(800.0);
			}
			List<ReferenceInfo> list8 = new List<ReferenceInfo>();
			Line crossLine = YJKLineEx.YJKGetBound(xyz3, xyz4);
			List<Grid> list9 = DimPublicFunc.LineCrossGrids(this.m_uiApplication, xyz3, xyz4, false);
			if (list9 != null && list9.Count > 0)
			{
				foreach (Grid grid in list9)
				{
					DimPublicFunc.GetGridDimRef(this.m_uiApplication, grid, crossLine, ref list8);
				}
			}
			foreach (Wall wall in list)
			{
				DimPublicFunc.GetWallDimRef(this.m_uiApplication, wall, crossLine, true, ref list8, true);
			}
			List<Element> list10 = new List<Element>();
			List<Element> list11 = this.ElementsBetweenTwoPt(xyz3, xyz4, BuiltInCategory.OST_Columns);
			List<Element> list12 = this.ElementsBetweenTwoPt(xyz3, xyz4, BuiltInCategory.OST_StructuralColumns);
			if (list11 != null)
			{
				list10.AddRange(list11);
			}
			if (list12 != null)
			{
				list10.AddRange(list12);
			}
			if (list10.Count > 0)
			{
				foreach (Element elem in list10)
				{
					DimPublicFunc.GetElementDimRef(this.m_uiApplication, elem, crossLine, ref list8);
				}
			}
			XYZ pt = xyz4 + (xyz4 - xyz3);
			list8.Sort(new DistanceComparer(DimPublicFunc.To2d(pt)));
			for (int i = 0; i < list8.Count; i++)
			{
				ReferenceInfo referenceInfo = list8[i];
				for (int j = i + 1; j < list8.Count; j++)
				{
					if (referenceInfo.ThePosition.DistanceTo(list8[j].ThePosition) < 0.001)
					{
						list8.RemoveAt(j);
						j--;
					}
				}
			}
			ReferenceArray referenceArray = new ReferenceArray();
			foreach (ReferenceInfo referenceInfo2 in list8)
			{
				referenceArray.Append(referenceInfo2.TheReference);
			}
			Dimension dimension = DimPublicFunc.CreateLinearDim(this.m_document, referenceArray, xyz2, xyz6, 0);
			if (dimension != null)
			{
				DimPublicFunc.SetDimFlag(dimension, "DoorWindowDim");
			}
			this.m_document.Regenerate();
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public Result WallThickDim()
		{
			XYZ xyz = null;
			XYZ xyz2 = null;
			if (DimPublicFunc.PickPoint(this.m_uiDocument, "点取穿过墙的起点P1：", ref xyz) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			if (DimPublicFunc.PickPoint(this.m_uiDocument, "点取穿过墙的终点P2：", ref xyz2) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			xyz2 = new XYZ(xyz2.X, xyz2.Y, xyz.Z);
			if (xyz.DistanceTo(xyz2) < 0.001)
			{
				YJKMessageBox.Show("两点不能相距太近，请重新点取。");
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			List<Wall> lstWall = (from w in new FilteredElementCollector(this.m_document, this.m_document.ActiveView.Id).OfClass(typeof(Wall))
			select w as Wall).ToList<Wall>();
			List<Wall> list = DimPublicFunc.LineCrossWalls(this.m_uiApplication, lstWall, xyz, xyz2);
			if (list == null || list.Count < 1)
			{
				YJKMessageBox.Show("起终点之间没有墙体。");
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			DimPublicFunc.ClearSurfaceWall(ref list);
			Wall wall = null;
			Line line = YJKLineEx.YJKGetBound(xyz, xyz2);
			double num = double.MaxValue;
			foreach (Wall wall2 in list)
			{
				XYZ xyz3 = this.LineIntersectWall(line, wall2);
				if (xyz3 != null && (wall == null || xyz3.DistanceTo(xyz2) < num))
				{
					wall = wall2;
					num = xyz3.DistanceTo(xyz2);
				}
			}
			XYZ startPt = WallAssistFunc.GetStartPt(wall);
			XYZ endPt = WallAssistFunc.GetEndPt(wall);
			DimPublicFunc.SortPoint(ref startPt, ref endPt);
			XYZ xyz4 = new XYZ(xyz2.X, xyz2.Y, startPt.Z);
			XYZ xyz5 = Geometry.CalculateFootPoint(startPt, endPt, xyz4);
			XYZ xyz6 = (xyz4 - xyz5).Normalize();
			Line line2 = YJKLineEx.YJKGetBound(new XYZ(startPt.X, startPt.Y, xyz.Z), new XYZ(endPt.X, endPt.Y, xyz.Z));
			xyz4 = Geometry.IntersectWithTwoCurves(line, line2, xyz, false, false, this.m_application);
			XYZ xyz7 = xyz4 - xyz6 * 10.0;
			XYZ xyz8 = xyz4 + xyz6 * 10.0;
			XYZ vtDim = (endPt - startPt).Normalize();
			int num2 = 0;
			Line crossLine = YJKLineEx.YJKGetBound(xyz7, xyz8);
			foreach (Wall wall3 in list)
			{
				Wall wall4 = wall3 as Wall;
				if (!this.DimWallThick(wall4, crossLine, vtDim, xyz8))
				{
					num2++;
				}
			}
			if (num2 > 0)
			{
				YJKMessageBox.Show("不能提取到墙的标注信息。");
			}
			this.m_document.Regenerate();
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public Result WallCenterDim(WallCenterDimensionForm dlg, List<DimensionType> alignDimTypes, ref string message)
		{
			if (AssistFunc.GetCurrentViewLevel(this.m_document) == null)
			{
				message = "当前激活的View不是平面的View！";
				return Autodesk.Revit.UI.Result.Failed;
			}
			Transaction transaction = null;
			try
			{
				XYZ xyz = null;
                if ((int)DimPublicFunc.PickPoint(this.m_uiDocument, "起点：", ref xyz) == 1)
				{
					return Autodesk.Revit.UI.Result.Cancelled;
				}
				XYZ xyz2 = null;
                if ((int)DimPublicFunc.PickPoint(this.m_uiDocument, "终点：", ref xyz2) == 1)
				{
					return Autodesk.Revit.UI.Result.Cancelled;
				}
				Line assistLine = YJKLineEx.YJKGetBound(xyz, xyz2);
				transaction = new Transaction(this.m_document, "wallCenterDim");
				transaction.Start();
				IList<Element> list = ElementFiltering.FindSpecialElements(this.m_document, typeof(Wall), BuiltInCategory.OST_Walls);
				if (dlg.LableGrids)
				{
					foreach (Element item in ElementFiltering.FindSpecialElements(this.m_document, typeof(Grid), BuiltInCategory.OST_Grids))
					{
						list.Add(item);
					}
				}
				int num = 0;
				Curve curve = null;
				Line line = null;
				ReferenceArray referenceArray = new ReferenceArray();
				IntersectionResultArray intResultArray = null;
				if (this.GetWallCenterReference(list, xyz, xyz2, assistLine, intResultArray, ref num, ref curve, ref line, ref referenceArray, ref message) != null)
				{
					if (transaction != null && (int)transaction.GetStatus() == 1)
					{
						transaction.RollBack();
					}
					return Autodesk.Revit.UI.Result.Failed;
				}
				if (referenceArray.Size > 1)
				{
					this.m_docCreator.NewDimension(this.m_document.ActiveView, line, referenceArray).DimensionType = alignDimTypes[dlg.SelectDimTypeIndex];
				}
				transaction.Commit();
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				if (transaction != null && (int)transaction.GetStatus() == 1)
				{
					transaction.RollBack();
				}
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception ex)
			{
				if (transaction != null && (int)transaction.GetStatus() == 1)
				{
					transaction.RollBack();
				}
				message = ex.Message;
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public Result PtByPtDim(ref string message)
		{
			Result result;
			try
			{
				XYZ xyz = this.m_uiDocument.Selection.PickPoint("点取第一标注点：");
				XYZ xyz2 = this.m_uiDocument.Selection.PickPoint("点取第二标注点：");
				XYZ xyz3 = this.m_uiDocument.Selection.PickPoint("点取标注位置点：");
				this.m_uiDocument.Selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)3, "点取第一标注参照边");
				this.m_uiDocument.Selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)3, "点取第二标注参照边");
				Line line = YJKLineEx.YJKGetBound(xyz, xyz2);
				XYZ closestPointTo = CurveAssistFunc.GetClosestPointTo(this.m_uiApplication, line, xyz3, true);
				double num = closestPointTo.DistanceTo(xyz3);
				XYZ xyz4 = (xyz3 - closestPointTo).Normalize();
				ReferenceArray referenceArray = new ReferenceArray();
				SketchPlane sketchPlane = this.m_document.ActiveView.SketchPlane;
				Line line2 = YJKLineEx.YJKGetBound(xyz, xyz + xyz4 * 0.1);
				Reference reference = this.m_docCreator.NewModelCurve(line2, sketchPlane).GeometryCurve.Reference;
				referenceArray.Append(reference);
				Line line3 = YJKLineEx.YJKGetBound(xyz2, xyz2 + xyz4 * 0.1);
				Reference reference2 = this.m_docCreator.NewModelCurve(line3, sketchPlane).GeometryCurve.Reference;
				referenceArray.Append(reference2);
				Line line4 = YJKLineEx.YJKGetBound(xyz + xyz4 * num, xyz2 + xyz4 * num);
				Dimension dimension = this.m_docCreator.NewDimension(this.m_document.ActiveView, line4, referenceArray);
				for (;;)
				{
					XYZ xyz5 = this.m_uiDocument.Selection.PickPoint("点取其他标注点：");
					Line line5 = YJKLineEx.YJKGetBound(xyz5, xyz5 + xyz4 * 0.1);
					Reference reference3 = this.m_docCreator.NewModelCurve(line5, sketchPlane).GeometryCurve.Reference;
					referenceArray.Append(reference3);
					RevitDocumentExtension.DeleteElement(this.m_document, dimension);
					dimension = this.m_docCreator.NewDimension(this.m_document.ActiveView, line4, referenceArray);
				}
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception ex)
			{
				message += ex.Message;
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		public Result InDoorDim(DlgInDoorDim dlg)
		{
			XYZ xyz = null;
			XYZ xyz2 = null;
			if (DimPublicFunc.PickPoint(this.m_uiDocument, "点取穿过门的第一点P1：", ref xyz) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			if (DimPublicFunc.PickPoint(this.m_uiDocument, "点取穿过门的第二点P2：", ref xyz2) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			xyz2 = new XYZ(xyz2.X, xyz2.Y, xyz.Z);
			if (xyz.DistanceTo(xyz2) < 0.001)
			{
				YJKMessageBox.Show("两点不能相距太近，请重新点取。");
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			List<Element> list = new List<Element>();
			List<Element> list2 = this.ElementsBetweenTwoPt(xyz, xyz2, BuiltInCategory.OST_Doors);
			List<Element> list3 = this.ElementsBetweenTwoPt(xyz, xyz2, BuiltInCategory.OST_Windows);
			List<Element> list4 = this.ElementsBetweenTwoPt(xyz, xyz2, BuiltInCategory.OST_SpecialityEquipment);
			if (list2 != null)
			{
				list.AddRange(list2);
			}
			if (list3 != null)
			{
				list.AddRange(list3);
			}
			if (list4 != null)
			{
				list.AddRange(list4);
			}
			if (list.Count < 1)
			{
				YJKMessageBox.Show("两点之间没有当前楼层平面的门(窗）。");
				return Autodesk.Revit.UI.Result.Failed;
			}
			if (list.Count > 1)
			{
				YJKMessageBox.Show("两点只能穿过一个门(窗）。");
				return Autodesk.Revit.UI.Result.Failed;
			}
			FamilyInstance opening = list[0] as FamilyInstance;
			List<ReferenceInfo> list5 = new List<ReferenceInfo>();
			DimPublicFunc.GetOpeningSideDimRef(this.m_uiApplication, opening, ref list5);
			if (list5.Count < 2)
			{
				YJKMessageBox.Show("不能获取标注参照，请确定：\n1,门/窗插入点在中心;\n2,门窗不在墙末端;\n3,门窗边框与墙洞等宽。");
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			XYZ xyz3 = null;
			XYZ xyz4 = null;
			XYZ xyz5 = null;
			DimPublicFunc.GetOpeningPoint(this.m_uiApplication, opening, ref xyz4, ref xyz3, ref xyz5);
			xyz3 = DimPublicFunc.SetPointZ(xyz3, xyz.Z);
			xyz4 = DimPublicFunc.SetPointZ(xyz4, xyz.Z);
			XYZ xyz6 = Geometry.CalculateFootPoint(xyz3, xyz4, xyz);
			XYZ xyz7 = Geometry.CalculateFootPoint(xyz3, xyz4, xyz2);
			XYZ xyz8 = (xyz7 - xyz6).Normalize();
			if (xyz8.GetLength() < 0.001)
			{
				xyz8 = (xyz4 - xyz3).Normalize();
			}
			ReferenceInfo referenceInfo = null;
			ReferenceInfo referenceInfo2 = null;
			if (dlg.BaseType == 0)
			{
				referenceInfo = this.FindNearAxisRefInfo(opening, xyz8);
			}
			else if (dlg.BaseType == 1)
			{
				referenceInfo2 = this.FindNearColumnRefInfo(opening, xyz8, xyz2);
				if (referenceInfo2 == null)
				{
					referenceInfo2 = this.FindNearWallRefInfo(opening, xyz8, xyz2);
				}
			}
			else if (dlg.BaseType == 2)
			{
				referenceInfo = this.FindNearAxisRefInfo(opening, xyz8);
				referenceInfo2 = this.FindNearColumnRefInfo(opening, xyz8, xyz2);
				if (referenceInfo2 == null)
				{
					referenceInfo2 = this.FindNearWallRefInfo(opening, xyz8, xyz2);
				}
			}
			if (referenceInfo != null)
			{
				list5.Add(referenceInfo);
			}
			if (referenceInfo2 != null)
			{
				list5.Add(referenceInfo2);
			}
			list5.Sort(new DistanceComparer(xyz6));
			for (int i = 0; i < list5.Count; i++)
			{
				ReferenceInfo referenceInfo3 = list5[i];
				for (int j = i + 1; j < list5.Count; j++)
				{
					if (referenceInfo3.ThePosition.DistanceTo(list5[j].ThePosition) < 0.001)
					{
						list5.RemoveAt(j);
						j--;
					}
				}
			}
			ReferenceArray referenceArray = new ReferenceArray();
			foreach (ReferenceInfo referenceInfo4 in list5)
			{
				referenceArray.Append(referenceInfo4.TheReference);
			}
			XYZ vtDim = (xyz2 - xyz7).Normalize();
			Dimension dimension = DimPublicFunc.CreateLinearDim(this.m_document, referenceArray, xyz2, vtDim, 0);
			if (dimension != null)
			{
				DimPublicFunc.SetDimFlag(dimension, "DoorWindowDim");
			}
			this.m_document.Regenerate();
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result GetWallCenterReference(IList<Element> wallsAndGrids, XYZ ptStart, XYZ ptEnd, Line assistLine, IntersectionResultArray intResultArray, ref int index, ref Curve baseLine, ref Line dimLine, ref ReferenceArray arRef, ref string message)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Element element in wallsAndGrids)
			{
				Reference reference = null;
				Curve curve;
				if (element.GetType() == typeof(Wall))
				{
					Wall wall = element as Wall;
					reference = this.GetWallCenterPlaneReference(wall);
					if (reference == null)
					{
						continue;
					}
					curve = (wall.Location as LocationCurve).Curve;
				}
				else
				{
					if (!(element.GetType() == typeof(Grid)))
					{
						continue;
					}
					Grid grid = element as Grid;
					this.GetGridRef(grid, ref reference);
					if (reference == null)
					{
						continue;
					}
					curve = grid.Curve;
				}
				if (!curve.GetEndPoint(0).Z.Equals(ptStart.Z))
				{
					curve = DimPublicFunc.ChangeCurveElevation(curve, ptStart.Z);
				}
				assistLine.Intersect(curve, out intResultArray);
				if (intResultArray != null)
				{
					XYZ ptInt = intResultArray.get_Item(0).XYZPoint;
					XYZ closestPointTo = CurveAssistFunc.GetClosestPointTo(this.m_uiApplication, curve, ptInt, false);
					if (closestPointTo == null)
					{
						message = "未能获得标注位置点！";
						return Autodesk.Revit.UI.Result.Failed;
					}
					if (list.FindIndex((XYZ value) => value.IsAlmostEqualTo(ptInt)) == -1)
					{
                        if ((int)CurveAssistFunc.GetCurveType(curve) == 1)
						{
							if (index == 0)
							{
								baseLine = (curve as Line);
								arRef.Append(reference);
								XYZ xyz = LineAssistFunc.GetVector(baseLine as Line);
								xyz = RevitVersionFuncs.CreateRotationAtPoint(XYZ.BasisZ, Math.PI*.5, XYZ.Zero).OfVector(xyz);
								ptStart = closestPointTo;
								ptEnd = ptStart + xyz.Normalize() * 10000.0;
								dimLine = YJKLineEx.YJKGetBound(ptStart, ptEnd);
								index++;
							}
							else
							{
                                if ((int)CurveAssistFunc.GetCurveType(baseLine) != 1)
								{
									continue;
								}
								Line line = curve as Line;
								if (GeoUtil.IsParallel(LineAssistFunc.GetVector(baseLine as Line), LineAssistFunc.GetVector(line)))
								{
									arRef.Append(reference);
								}
							}
						}
						else
						{
                            if ((int)CurveAssistFunc.GetCurveType(curve) != 2)
							{
								continue;
							}
							if (index == 0)
							{
								baseLine = (curve as Arc);
								arRef.Append(reference);
								XYZ xyz = ArcAssistFunc.GetArcNormalVector(baseLine as Arc, closestPointTo);
								ptStart = closestPointTo;
								ptEnd = ptStart + xyz.Normalize() * 10000.0;
								dimLine = YJKLineEx.YJKGetBound(ptStart, ptEnd);
								index++;
							}
							else
							{
                                if ((int)CurveAssistFunc.GetCurveType(baseLine) != 2)
								{
									continue;
								}
								Arc arc = curve as Arc;
								if (this.IsEqualWith2DPoint(arc.Center, (baseLine as Arc).Center))
								{
									arRef.Append(reference);
								}
							}
						}
						list.Add(ptInt);
					}
				}
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private bool GetGridRef(Grid grid, ref Reference reference)
		{
			XYZ hyendPoint = RevitDocumentExtension.GetEndPoint(grid.Curve, 0);
			XYZ hyendPoint2 = RevitDocumentExtension.GetEndPoint(grid.Curve, 1);
			foreach (Curve curve in DimPublicFunc.GetElementCurves(this.m_document, grid))
			{
				XYZ hyendPoint3 = RevitDocumentExtension.GetEndPoint(curve, 0);
				XYZ hyendPoint4 = RevitDocumentExtension.GetEndPoint(curve, 1);
				XYZ xyz = null;
				XYZ xyz2 = null;
				Geometry.OverlapType overlapType = Geometry.IsOverlapOfTwoLine(DimPublicFunc.To2d(hyendPoint), DimPublicFunc.To2d(hyendPoint2), DimPublicFunc.To2d(hyendPoint3), DimPublicFunc.To2d(hyendPoint4), ref xyz, ref xyz2, true, 1E-09);
                if ((int)overlapType == 1 || (int)overlapType == 2 || (int)overlapType == 3 || (int)overlapType == 4)
				{
					reference = curve.Reference;
					break;
				}
			}
			return true;
		}

		protected Reference GetWallCenterPlaneReference(Wall wall)
		{
			Reference result = null;
			Curve curve = (wall.Location as LocationCurve).Curve;
			if (curve.GetType() == typeof(Line))
			{
				Line line = curve as Line;
				Options options = this.m_application.Create.NewGeometryOptions();
				options.IncludeNonVisibleObjects = true;
				options.ComputeReferences = true;
				options.View = this.m_uiDocument.Document.ActiveView;
				using (List<GeometryObject>.Enumerator enumerator = RevitVersionFuncs.GetGeometryObjectArray(wall.get_Geometry(options)).GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						GeometryObject geometryObject = enumerator.Current;
						Line line2 = geometryObject as Line;
						if (!(line2 == null) && line2.IsBound && DimPublicFunc.IsParallel(line2.Direction, line.Direction) && Geometry.Is_Points_Collinear(DimPublicFunc.To2d(RevitDocumentExtension.GetEndPoint(line2, 0)), DimPublicFunc.To2d(RevitDocumentExtension.GetEndPoint(line, 0)), DimPublicFunc.To2d(RevitDocumentExtension.GetEndPoint(line, 1)), 1E-09) && line2.Reference != null)
						{
							result = line2.Reference;
							return result;
						}
					}
					return result;
				}
			}
			if (curve.GetType() == typeof(Arc))
			{
				Arc arc = curve as Arc;
				Options options2 = this.m_application.Create.NewGeometryOptions();
				options2.IncludeNonVisibleObjects = true;
				options2.ComputeReferences = true;
				options2.View = this.m_uiDocument.Document.ActiveView;
				foreach (GeometryObject geometryObject2 in RevitVersionFuncs.GetGeometryObjectArray(wall.get_Geometry(options2)))
				{
					Arc arc2 = geometryObject2 as Arc;
					if (!(arc2 == null) && this.IsEqualWith2DPoint(arc.Center, arc2.Center) && Geometry.IsEqual(arc.Radius, arc2.Radius) && arc2.Reference != null)
					{
						result = arc2.Reference;
						return result;
					}
				}
			}
			return result;
		}

		private bool IsEqualWith2DPoint(XYZ pt1, XYZ pt2)
		{
			return Geometry.Lessthan_Or_Equal(Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2.0) + Math.Pow(pt1.Y - pt2.Y, 2.0)), 0.0001);
		}

		private List<Wall> WallsOnAxis(Grid grid, double dElev)
		{
			if (grid.Curve.GetType() != typeof(Line))
			{
				return null;
			}
			List<Element> list = new FilteredElementCollector(this.m_document, this.m_document.ActiveView.Id).OfClass(typeof(Wall)).OfCategory(BuiltInCategory.OST_Walls).ToList<Element>();
			if (list == null || list.Count < 1)
			{
				return null;
			}
			Curve curve = DimPublicFunc.ChangeCurveElevation(grid.Curve, dElev);
			XYZ hyendPoint = RevitDocumentExtension.GetEndPoint(curve, 0);
			XYZ hyendPoint2 = RevitDocumentExtension.GetEndPoint(curve, 1);
			List<Wall> list2 = new List<Wall>();
			foreach (Element element in list)
			{
				Wall wall = element as Wall;
				LocationCurve locationCurve = wall.Location as LocationCurve;
				if (!(locationCurve.Curve.GetType() != typeof(Line)))
				{
					Curve curve2 = DimPublicFunc.ChangeCurveElevation(locationCurve.Curve, dElev);
					if (DimPublicFunc.TwoLineOnOne(hyendPoint, hyendPoint2, RevitDocumentExtension.GetEndPoint(curve2, 0), RevitDocumentExtension.GetEndPoint(curve2, 1)))
					{
						list2.Add(wall);
					}
				}
			}
			return list2;
		}

		private List<Wall> GetWallOnLevel(List<Wall> lstAllWall, ElementId levelId)
		{
			List<Wall> list = new List<Wall>();
			foreach (Wall wall in lstAllWall)
			{
				if (wall.LevelId == levelId)
				{
					list.Add(wall);
				}
			}
			return list;
		}

		private List<Wall> GetWallsOnTopLevel(List<Wall> lstAllWall)
		{
			ElementId elementId = null;
			double num = double.MinValue;
			foreach (Wall wall in lstAllWall)
			{
				double z = WallAssistFunc.GetStartPt(wall).Z;
				if (elementId == null || z - num > 0.001)
				{
					elementId = wall.LevelId;
					num = z;
				}
			}
			List<Wall> list = new List<Wall>();
			foreach (Wall wall2 in lstAllWall)
			{
				if (wall2.LevelId == elementId)
				{
					list.Add(wall2);
				}
			}
			return list;
		}

		private List<Element> ElementsBetweenTwoPt(XYZ pt1, XYZ pt2, BuiltInCategory elemType)
		{
			List<Element> list = DimPublicFunc.ElementsAtBoundingBox(this.m_document, pt1, pt2, elemType);
			if (list == null || list.Count < 1)
			{
				return null;
			}
			Line line = YJKLineEx.YJKGetBound(pt1, pt2);
			List<Element> result = new List<Element>();
            if ((int)elemType == -2000023)
			{
				this.LineCrossDoors(line, list, ref result);
			}
            else if ((int)elemType == -2000014)
			{
				this.LineCrossWindows(line, list, ref result);
			}
            else if ((int)elemType == -2000011)
			{
				this.LineCrossWalls(line, list, ref result);
			}
			else
			{
                if ((int)elemType != -2001350)
				{
					return list;
				}
				this.LineCrossElevators(line, list, ref result);
			}
			return result;
		}

		private void LineCrossDoors(Line line, List<Element> lstElement, ref List<Element> lstCrossDoor)
		{
			XYZ hyendPoint = RevitDocumentExtension.GetEndPoint(line, 0);
			foreach (Element element in lstElement)
			{
				if (element.Category.Id.IntegerValue == -2000023)
				{
					XYZ xyz = null;
					XYZ xyz2 = null;
					XYZ xyz3 = null;
					FamilyInstance opening = element as FamilyInstance;
					DimPublicFunc.GetOpeningPoint(this.m_uiApplication, opening, ref xyz, ref xyz2, ref xyz3);
					Line line2 = YJKLineEx.YJKGetBound(new XYZ(xyz2.X, xyz2.Y, hyendPoint.Z), new XYZ(xyz.X, xyz.Y, hyendPoint.Z));
					if (Geometry.IntersectWithTwoCurves(line, line2, hyendPoint, false, false, this.m_application) != null)
					{
						lstCrossDoor.Add(element);
					}
				}
			}
		}

		private void LineCrossElevators(Line line, List<Element> lstElement, ref List<Element> lstCrossElevator)
		{
			XYZ hyendPoint = RevitDocumentExtension.GetEndPoint(line, 0);
			foreach (Element element in lstElement)
			{
				if (element.Category.Id.IntegerValue == -2001350)
				{
					Parameter parameter = RevitElementExtension.GetParameter(element, "电梯类型");
					if (parameter != null)
					{
						XYZ xyz = null;
						XYZ xyz2 = null;
						XYZ xyz3 = null;
						FamilyInstance opening = element as FamilyInstance;
						DimPublicFunc.GetOpeningPoint(this.m_uiApplication, opening, ref xyz, ref xyz2, ref xyz3);
						Line line2 = YJKLineEx.YJKGetBound(new XYZ(xyz2.X, xyz2.Y, hyendPoint.Z), new XYZ(xyz.X, xyz.Y, hyendPoint.Z));
						if (Geometry.IntersectWithTwoCurves(line, line2, hyendPoint, false, false, this.m_application) != null)
						{
							lstCrossElevator.Add(element);
						}
					}
				}
			}
		}

		private void LineCrossWindows(Line line, List<Element> lstElement, ref List<Element> lstCrossWindow)
		{
			XYZ hyendPoint = RevitDocumentExtension.GetEndPoint(line, 0);
			foreach (Element element in lstElement)
			{
				if (element.Category.Id.IntegerValue == -2000014)
				{
					XYZ xyz = null;
					XYZ xyz2 = null;
					XYZ xyz3 = null;
					FamilyInstance opening = element as FamilyInstance;
					DimPublicFunc.GetOpeningPoint(this.m_uiApplication, opening, ref xyz, ref xyz2, ref xyz3);
					Line line2 = YJKLineEx.YJKGetBound(new XYZ(xyz2.X, xyz2.Y, hyendPoint.Z), new XYZ(xyz.X, xyz.Y, hyendPoint.Z));
					if (Geometry.IntersectWithTwoCurves(line, line2, hyendPoint, false, false, this.m_application) != null)
					{
						lstCrossWindow.Add(element);
					}
				}
			}
		}

		private void LineCrossWalls(Line line, List<Element> lstElement, ref List<Element> lstCrossWall)
		{
			foreach (Element element in lstElement)
			{
				if (!(element.GetType() != typeof(Wall)))
				{
					Wall wall = element as Wall;
					if (this.LineIntersectWall(line, wall) != null)
					{
						lstCrossWall.Add(element);
					}
				}
			}
		}

		private ReferenceInfo FindNearAxisRefInfo(FamilyInstance opening, XYZ vtFindDir)
		{
			XYZ xyz = null;
			XYZ xyz2 = null;
			XYZ xyz3 = null;
			DimPublicFunc.GetOpeningPoint(this.m_uiApplication, opening, ref xyz2, ref xyz, ref xyz3);
			XYZ xyz4 = (xyz - xyz2).Normalize();
			XYZ xyz5 = (vtFindDir.AngleTo(xyz4) < 0.001) ? xyz : xyz2;
			XYZ xyz6 = xyz5 + vtFindDir * 30.0;
			List<Grid> list = DimPublicFunc.LineCrossGrids(this.m_uiApplication, xyz5, xyz6, false);
			if (list == null || list.Count < 1)
			{
				return null;
			}
			Line crossLine = YJKLineEx.YJKGetBound(xyz5, xyz6);
			List<ReferenceInfo> lstRefInfo = new List<ReferenceInfo>();
			foreach (Grid grid in list)
			{
				DimPublicFunc.GetGridDimRef(this.m_uiApplication, grid, crossLine, ref lstRefInfo);
			}
			return this.GetNearRefInfo(xyz5, lstRefInfo);
		}

		private ReferenceInfo FindNearColumnRefInfo(FamilyInstance opening, XYZ vtFindDir, XYZ ptUserPick)
		{
			Element host = opening.Host;
			if (host == null)
			{
				return null;
			}
			Wall wall = host as Wall;
			if (wall == null)
			{
				return null;
			}
			Line line = (wall.Location as LocationCurve).Curve as Line;
			if (line == null)
			{
				return null;
			}
			XYZ hyendPoint = RevitDocumentExtension.GetEndPoint(line, 0);
			XYZ hyendPoint2 = RevitDocumentExtension.GetEndPoint(line, 1);
			XYZ point = (opening.Location as LocationPoint).Point;
			XYZ xyz = new XYZ(point.X, point.Y, hyendPoint.Z);
			XYZ xyz2 = (vtFindDir.AngleTo(hyendPoint2 - hyendPoint) < 0.001) ? hyendPoint2 : hyendPoint;
			Line crossLine = YJKLineEx.YJKGetBound(xyz, xyz2);
			xyz2 += vtFindDir * wall.Width;
			List<Element> list = new List<Element>();
			List<Element> list2 = this.ElementsBetweenTwoPt(xyz, xyz2, BuiltInCategory.OST_Columns);
			List<Element> list3 = this.ElementsBetweenTwoPt(xyz, xyz2, BuiltInCategory.OST_StructuralColumns);
			if (list2 != null)
			{
				list.AddRange(list2);
			}
			if (list3 != null)
			{
				list.AddRange(list3);
			}
			if (list.Count < 1)
			{
				return null;
			}
			List<ReferenceInfo> lstRefInfo = new List<ReferenceInfo>();
			foreach (Element elem in list)
			{
				DimPublicFunc.GetElementDimRef(this.m_uiApplication, elem, crossLine, ref lstRefInfo);
			}
			ReferenceInfo nearRefInfo = this.GetNearRefInfo(xyz, lstRefInfo);
			if (nearRefInfo == null)
			{
				return null;
			}
			ReferenceInfo referenceInfo = null;
			XYZ xyz3 = new XYZ(ptUserPick.X, ptUserPick.Y, hyendPoint.Z);
			XYZ xyz4 = Geometry.CalculateFootPoint(hyendPoint, hyendPoint2, xyz3);
			XYZ xyz5 = (xyz3 - xyz4).Normalize();
			XYZ pt = xyz + xyz5 * (wall.Width / 1.5);
			XYZ pt2 = xyz2 + xyz5 * (wall.Width / 1.5);
			List<Wall> list4 = DimPublicFunc.LineCrossWalls(this.m_uiApplication, pt, pt2);
			if (list4 != null && list4.Count > 1)
			{
				List<ReferenceInfo> lstRefInfo2 = new List<ReferenceInfo>();
				foreach (Wall wall2 in list4)
				{
					DimPublicFunc.GetWallThickRef(this.m_uiApplication, wall2, crossLine, (Autodesk.Revit.DB.ViewDetailLevel)1, ref lstRefInfo2);
				}
				referenceInfo = this.GetNearRefInfo(xyz, lstRefInfo2);
			}
			if (referenceInfo != null)
			{
				XYZ xyz6 = DimPublicFunc.To2d(xyz);
				double num = xyz6.DistanceTo(referenceInfo.ThePosition);
				double num2 = xyz6.DistanceTo(nearRefInfo.ThePosition);
				if (num < num2)
				{
					return referenceInfo;
				}
			}
			return nearRefInfo;
		}

		private ReferenceInfo FindNearWallRefInfo(FamilyInstance opening, XYZ vtFindDir, XYZ ptUserPick)
		{
			Element host = opening.Host;
			if (host == null)
			{
				return null;
			}
			Wall wall = host as Wall;
			if (wall == null)
			{
				return null;
			}
			Line line = (wall.Location as LocationCurve).Curve as Line;
			if (line == null)
			{
				return null;
			}
			line = DimPublicFunc.ExtendLine(line, 2, wall.Width);
			XYZ hyendPoint = RevitDocumentExtension.GetEndPoint(line, 0);
			XYZ hyendPoint2 = RevitDocumentExtension.GetEndPoint(line, 1);
			XYZ point = (opening.Location as LocationPoint).Point;
			XYZ xyz = Geometry.CalculateFootPoint(hyendPoint, hyendPoint2, DimPublicFunc.SetPointZ(point, hyendPoint.Z));
			XYZ xyz2 = (vtFindDir.AngleTo(hyendPoint2 - hyendPoint) < 0.001) ? hyendPoint2 : hyendPoint;
			Line crossLine = YJKLineEx.YJKGetBound(xyz, xyz2);
			XYZ xyz3 = new XYZ(ptUserPick.X, ptUserPick.Y, hyendPoint.Z);
			XYZ xyz4 = Geometry.CalculateFootPoint(hyendPoint, hyendPoint2, xyz3);
			XYZ xyz5 = (xyz3 - xyz4).Normalize();
			XYZ xyz6 = xyz + xyz5 * wall.Width;
			XYZ pt = xyz2 + xyz5 * wall.Width;
			List<Wall> list = DimPublicFunc.LineCrossWalls(this.m_uiApplication, xyz6, pt);
			if (list != null && list.Count > 0)
			{
				List<ReferenceInfo> lstRefInfo = new List<ReferenceInfo>();
				foreach (Wall wall2 in list)
				{
                    DimPublicFunc.GetWallThickRef(this.m_uiApplication, wall2, crossLine, (Autodesk.Revit.DB.ViewDetailLevel)1, ref lstRefInfo);
				}
				ReferenceInfo nearRefInfo = this.GetNearRefInfo(xyz6, lstRefInfo);
				if (nearRefInfo != null)
				{
					return nearRefInfo;
				}
			}
			xyz6 = xyz2 - vtFindDir * (wall.Width * 2.0) - xyz5 * wall.Width;
			pt = xyz2 - xyz5 * wall.Width;
			list = DimPublicFunc.LineCrossWalls(this.m_uiApplication, xyz6, pt);
			if (list == null || list.Count != 1)
			{
				List<ReferenceInfo> lstRefInfo2 = new List<ReferenceInfo>();
				DimPublicFunc.GetWallDimRef(this.m_uiApplication, wall, crossLine, true, ref lstRefInfo2, true);
				return this.GetNearRefInfo(xyz2, lstRefInfo2);
			}
			Wall wall3 = list[0];
			List<ReferenceInfo> list2 = new List<ReferenceInfo>();
            DimPublicFunc.GetWallThickRef(this.m_uiApplication, wall3, crossLine, (Autodesk.Revit.DB.ViewDetailLevel)1, ref list2);
			if (list2 == null || list2.Count != 2)
			{
				return null;
			}
			Line line2 = YJKLineEx.YJKGetBound(hyendPoint + xyz5 * wall.Width, hyendPoint2 + xyz5 * wall.Width);
			Line line3 = (wall3.Location as LocationCurve).Curve as Line;
			if (Geometry.IntersectWithTwoCurves(line2, line3, RevitDocumentExtension.GetEndPoint(line2, 0), false, false, this.m_application) == null)
			{
				return this.GetFarRefInfo(xyz, list2);
			}
			return this.GetNearRefInfo(xyz, list2);
		}

		private ReferenceInfo GetNearRefInfo(XYZ ptBase, List<ReferenceInfo> lstRefInfo)
		{
			ReferenceInfo referenceInfo = null;
			XYZ xyz = DimPublicFunc.To2d(ptBase);
			double num = double.MaxValue;
			foreach (ReferenceInfo referenceInfo2 in lstRefInfo)
			{
				double num2 = xyz.DistanceTo(referenceInfo2.ThePosition);
				if (referenceInfo == null || num2 < num)
				{
					referenceInfo = referenceInfo2;
					num = num2;
				}
			}
			return referenceInfo;
		}

		private ReferenceInfo GetFarRefInfo(XYZ ptBase, List<ReferenceInfo> lstRefInfo)
		{
			ReferenceInfo referenceInfo = null;
			XYZ xyz = DimPublicFunc.To2d(ptBase);
			double num = 0.0;
			foreach (ReferenceInfo referenceInfo2 in lstRefInfo)
			{
				double num2 = xyz.DistanceTo(referenceInfo2.ThePosition);
				if (referenceInfo == null || num2 > num)
				{
					referenceInfo = referenceInfo2;
					num = num2;
				}
			}
			return referenceInfo;
		}

		private XYZ LineIntersectWall(Line line, Wall wall)
		{
			LocationCurve locationCurve = wall.Location as LocationCurve;
			if (locationCurve.Curve.GetType() != typeof(Line))
			{
				return null;
			}
			XYZ hyendPoint = RevitDocumentExtension.GetEndPoint(line, 0);
			Curve curve = DimPublicFunc.ChangeCurveElevation(locationCurve.Curve, hyendPoint.Z);
			return Geometry.IntersectWithTwoCurves(line, curve, hyendPoint, false, false, this.m_application);
		}

		private XYZ FindNearDimInter(XYZ ptStart, XYZ ptEnd)
		{
			List<Element> list = new FilteredElementCollector(this.m_document, this.m_document.ActiveView.Id).OfClass(typeof(Dimension)).ToList<Element>();
			if (list == null || list.Count < 1)
			{
				return null;
			}
			XYZ xyz = null;
			double num = double.MaxValue;
			Level currentViewLevel = AssistFunc.GetCurrentViewLevel(this.m_document);
			Line line = YJKLineEx.YJKGetBound(ptStart, ptEnd);
			foreach (Element element in list)
			{
				Dimension dimension = element as Dimension;
				if (dimension.View != null && dimension.View.GenLevel != null && !(dimension.View.GenLevel.Id != currentViewLevel.Id) && dimension.DimensionShape == null)
				{
					Line line2 = DimPublicFunc.GetLinearDimSizeLine(dimension);
					if (!(line2 == null))
					{
						line2 = DimPublicFunc.ChangeLineElevation(line2, ptStart.Z);
						XYZ xyz2 = Geometry.IntersectWithTwoCurves(line, line2, ptStart, false, false, this.m_application);
						if (xyz2 != null && (xyz == null || ptStart.DistanceTo(xyz2) < num))
						{
							xyz = xyz2;
							num = ptStart.DistanceTo(xyz2);
						}
					}
				}
			}
			return xyz;
		}

		private bool DimWallThick(Wall wall, Line crossLine, XYZ vtDim, XYZ ptDim)
		{
			List<ReferenceInfo> list = new List<ReferenceInfo>();
			DimPublicFunc.GetWallThickRef(this.m_uiApplication, wall, crossLine, this.m_document.ActiveView.DetailLevel, ref list);
			if (list.Count != 2)
			{
				return false;
			}
			List<Grid> list2 = DimPublicFunc.LineCrossGrids(this.m_uiApplication, list[0].ThePosition, list[1].ThePosition, false);
			if (list2 != null && list2.Count == 1)
			{
				DimPublicFunc.GetGridDimRef(this.m_uiApplication, list2[0], crossLine, ref list);
			}
			ReferenceArray referenceArray = new ReferenceArray();
			foreach (ReferenceInfo referenceInfo in list)
			{
				referenceArray.Append(referenceInfo.TheReference);
			}
			Dimension dimension = DimPublicFunc.CreateWallThickDim(this.m_document, referenceArray, ptDim, vtDim);
			if (dimension != null)
			{
				DimPublicFunc.SetDimFlag(dimension, "WallThickDim");
			}
			return true;
		}

		private Wall GetMaxThickWall(List<Wall> lstOnLevelWall)
		{
			Wall wall = null;
			double num = 0.0;
			foreach (Wall wall2 in lstOnLevelWall)
			{
				if (wall == null || num < wall2.Width)
				{
					wall = wall2;
					num = wall2.Width;
				}
			}
			return wall;
		}

		private void FilterWallWithoutDoorAndWind(ref List<Wall> lstDimWall)
		{
			if (0 >= lstDimWall.Count)
			{
				return;
			}
			for (int i = 0; i < lstDimWall.Count; i++)
			{
				if (lstDimWall[i].FindInserts(false, true, true, true).Count == 0)
				{
					lstDimWall.RemoveAt(i);
					i--;
				}
			}
		}

		protected UIApplication m_uiApplication;

		protected UIDocument m_uiDocument;

		protected Autodesk.Revit.ApplicationServices.Application m_application;

        protected Autodesk.Revit.DB.Document m_document;

        protected Autodesk.Revit.Creation.Application m_appCreator;

        protected Autodesk.Revit.Creation.Document m_docCreator;

		private const double precision = 0.001;
	}
}
